﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CashFlow.Repository;
using System.Diagnostics.Contracts;
using CashFlow.Common;
using CashFlow.Entities;

namespace CashFlow.AzureRepository
{
	public class AzureBillRepository : AzureRepositoryBase, IBillRepository
	{
		#region Constructors
		/// <summary>
		/// Initializes a new instance of the <see cref="T:AzureBillRepository"/> class.
		/// </summary>
		public AzureBillRepository() : base()
		{

		}
		/// <summary>
		/// Initializes a new instance of the <see cref="T:AzureBillRepository"/> class.
		/// </summary>
		public AzureBillRepository(string tenantId) : base(tenantId)
		{
		}
		#endregion

		#region Table operations.
		public IEnumerable<Bill> GetAll()
		{
			Contract.Requires(string.IsNullOrEmpty(tenantId), "Object should have tenantId assigned.");

			var dbEntities = GetAllByKey<BillAzure>(Constants.TableNames.Bills, tenantId).ToList();
			var entities = dbEntities.Select(dbe => (Bill)dbe);
			return entities;
		}

		public Bill GetById(string id)
		{
			Contract.Requires(!string.IsNullOrEmpty(tenantId), "Object should have tenantId assigned.");
			Contract.Requires(!string.IsNullOrEmpty(id), "id cannot be null.");

			Bill entity = null;
			var dbEntity = GetByKeys<BillAzure>(Constants.TableNames.Bills, tenantId, id);
			//TODO: vvs p3 this check can be moved to the base class (it will be done for all tables).
			if (dbEntity != null)
			{
				entity = (Bill)dbEntity;
			}

			return entity;
		}

		public void Create(Bill bill)
		{
			Contract.Requires(!string.IsNullOrEmpty(tenantId), "Object should have tenantId assigned.");
			Contract.Requires(bill != null, "bill cannot be null.");

			//TODO: vvs p2 save with retry.
			var azureEntity = (BillAzure)bill;
			db.AddObject(Constants.TableNames.Bills, azureEntity);
			db.SaveChanges();
		}

		public void Update(Bill bill)
		{
			var dbEntity = (BillAzure)bill;
			Update(Constants.TableNames.Bills, dbEntity);
		}

		public void Delete(string id)
		{
			//TODO: vvs p3 refactor: same contracts in all modification methods.
			//TODO: vvs p1 catch exception, log it, add to error indicator.
			//TODO: vvs p1 duplicate deletion (same pk, rk are in deleted table already).
			//TODO: vvs p1 item not found in the existing bill table.
			Contract.Requires(!string.IsNullOrEmpty(tenantId), "Object should have tenantId assigned.");
			Contract.Requires(!string.IsNullOrEmpty(id), "bill id cannot be null.");

			var dbEntity = GetByKeys<BillAzure>(Constants.TableNames.Bills, tenantId, id);
			var deleteClone = dbEntity.Clone();
			db.AddObject(Constants.TableNames.Deletes, deleteClone);
			db.DeleteObject(dbEntity);
			db.SaveChanges();
		}

		public void UnDelete(string id)
		{
			//TODO: vvs p2 remove contracts - I do it in async way (should I?).
			//TODO: vvs p3 refactor: same contracts in all modification methods.
			//TODO: vvs p1 catch exception, log it, add to error indicator.
			//TODO: vvs p1 duplicate deletion (same pk, rk are in deleted table already).
			//TODO: vvs p1 item not found in the existing bill table.
			Contract.Requires(!string.IsNullOrEmpty(tenantId), "Object should have tenantId assigned.");
			Contract.Requires(!string.IsNullOrEmpty(id), "bill id cannot be null.");

			var deleteClone = GetByKeys<BillAzure>(Constants.TableNames.Deletes, tenantId, id);
			var dbEntity = deleteClone.Clone();
			db.AddObject(Constants.TableNames.Bills, dbEntity);
			db.DeleteObject(deleteClone);
			db.SaveChanges();
		}
		#endregion
	}
}
